import cryptoFramework from '@ohos.security.cryptoFramework'

let algName = "RSA1024|PRIMES_2"
let transformation = "RSA1024|PKCS1"
let maxEncryptBlockSize = 117
let maxDecryptBlockSize = 128

export class RSAUtils {

  /**
   * 生成RSA秘钥对
   * @returns
   */
  static genRsaKeyPair(): Promise<cryptoFramework.KeyPair> {
    return cryptoFramework.createAsyKeyGenerator(algName).generateKeyPair()
  }

  /**
   * 转换RSA秘钥
   * @param pubKey 公钥
   * @param priKey 私钥
   * @returns
   */
  static convertKeyPair(pubKey: Uint8Array, priKey: Uint8Array): Promise<cryptoFramework.KeyPair> {
    let pubKeyData = {
      data: pubKey
    }
    let priKeyData = {
      data: priKey
    }
    return cryptoFramework.createAsyKeyGenerator(algName).convertKey(pubKeyData, priKeyData)
  }


  /**
   * 分段加密
   * @param priKey
   * @param cipherText
   * @returns
   */
  static async rsaEncryptBySegment(pubKey: cryptoFramework.PubKey, plainText: cryptoFramework.DataBlob) {
    let cipher = cryptoFramework.createCipher(transformation);
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null);
    let plainTextSplitLen = 64;
    let cipherText = new Uint8Array();
    for (let i = 0; i < plainText.data.length; i += plainTextSplitLen ) {
      let updateMessage = plainText.data.subarray(i, i + plainTextSplitLen );
      let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
      // 将原文按64字符进行拆分，循环调用doFinal进行加密，使用1024bit密钥时，每次加密生成128字节长度的密文
      let updateOutput = await cipher.doFinal(updateMessageBlob);
      let mergeText = new Uint8Array(cipherText.length + updateOutput.data.length);
      mergeText.set(cipherText);
      mergeText.set(updateOutput.data, cipherText.length);
      cipherText = mergeText;
    }
    let cipherBlob: cryptoFramework.DataBlob = { data: cipherText };
    return cipherBlob;
  }

  /**
   * 分段解密
   * @param priKey
   * @param cipherText
   * @returns
   */
  static async rsaDecryptBySegment(priKey: cryptoFramework.PriKey, cipherText: cryptoFramework.DataBlob) {
    let decoder = cryptoFramework.createCipher(transformation);
    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, priKey, null);
    let cipherTextSplitLen = 128; // RSA密钥每次加密生成的密文字节长度计算方式：密钥位数/8
    let decryptText = new Uint8Array();
    for (let i = 0; i < cipherText.data.length; i += cipherTextSplitLen) {
      let updateMessage = cipherText.data.subarray(i, i + cipherTextSplitLen);
      let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
      // 将密文按128字节进行拆分解密，得到原文后进行拼接
      let updateOutput = await decoder.doFinal(updateMessageBlob);
      let mergeText = new Uint8Array(decryptText.length + updateOutput.data.length);
      mergeText.set(decryptText);
      mergeText.set(updateOutput.data, decryptText.length);
      decryptText = mergeText;
    }
    let decryptBlob: cryptoFramework.DataBlob = { data: decryptText };
    return decryptBlob;
  }

  /**
   * 加密
   */
  static encrypt(pubKey: cryptoFramework.PubKey, data: Uint8Array): Promise<Uint8Array> {
    return new Promise(function (resolve, reject) {
      let dataArray = RSAUtils.splitArray(data, maxEncryptBlockSize)
      let promiseArray = []

      dataArray.forEach((value) => {
        let cipher = cryptoFramework.createCipher(transformation)
        let promise = cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null).then(() => {
          return cipher.doFinal({
            data: value
          })
        })
        promiseArray.push(promise)
      })

      let resultArray = []
      Promise.all(promiseArray).then((value) => {
        value.forEach((item) => {
          item.data.forEach(data => {
            resultArray.push(data)
          })
        })
        resolve(new Uint8Array(resultArray))
      }).catch(err => {
        reject(err)
      })
    })
  }

  /**
   * 解密
   */
  static decrypt(priKey: cryptoFramework.PriKey, data: Uint8Array): Promise<Uint8Array> {
    return new Promise(function (resolve, reject) {
      let dataArray = RSAUtils.splitArray(data, maxDecryptBlockSize)
      // let resultArray = []
      let promiseArray = []

      dataArray.forEach((value) => {
        let cipher = cryptoFramework.createCipher(transformation)
        let promise = cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, priKey, null).then(() => {
          return cipher.doFinal({
            data: value
          })
        })
        promiseArray.push(promise)
      })

      let resultArray = []
      Promise.all(promiseArray).then((value) => {
        value.forEach((item) => {
          item.data.forEach(data => {
            resultArray.push(data)
          })
        })
        resolve(new Uint8Array(resultArray))
      }).catch(err => {
        reject(err)
      })
    })
  }

  static splitArray(array, size) {
    let dataArray = [];
    for (let i = 0;i < array.length; i += size) {
      if (array.length - i >= size) {
        dataArray.push(array.subarray(i, i + size))
      } else {
        dataArray.push(array.subarray(i, array.length))
      }
    }
    return dataArray
  }

}



